// Copyright (c) 2007, Brian Duff

// See LICENSE for full license details.

package org.dubh.jdant;

import java.io.File;
import java.io.IOException;

import java.net.URL;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.FileSet;


/**
 * An ant task that reads properties from a JDeveloper project file.
 *
 * @author brian.duff@dubh.org
 */
public final class GetProjectPropertiesTask extends Task
{
  private File _project;
  private boolean _echo;
  private List<FileSet> _filesets = new ArrayList<FileSet>();
  
  /**
   * Sets whether this task will echo the properties and values it is setting
   * to the ant log. <tt>false</tt> by default.
   * 
   * @param echo if <tt>true</tt> this task will echo to the log. 
   */
  public void setEcho( boolean echo )
  {
    _echo = echo;
  }
  
  /**
   * Sets the project file to read. A project file is required.
   * 
   * @param project the project file to read.
   */
  public void setProject( File project )
  {
    _project = project;
  }
  
  public void addFileset( FileSet fileset )
  {
    this._filesets.add( fileset );
  }

  private void checkAttributes()
  {
    if ( _project != null && !_filesets.isEmpty() )
      throw new BuildException( "Must use file or fileset, not both" );
      
    if ( _filesets.isEmpty() && _project == null )
      throw new BuildException( "project attribute is required." );

    if ( _filesets.isEmpty()  && !_project.isFile() )
      throw new BuildException( "project file " + _project + " does not exist" );
  }

  @Override
  public void execute() throws BuildException 
  {
    checkAttributes();
    
    if ( _project != null ) processProject( _project );
    for ( FileSet fs : _filesets )
    {
      DirectoryScanner ds = fs.getDirectoryScanner( getProject() );
      String[] files = ds.getIncludedFiles();
      for ( String file : files )
      {
        processProject( new File( ds.getBasedir(), file ) );
      }
    }
  }

  private void processProject( File project )
  {
    try
    {
      String oracleHome = getProject().getProperty( "oracle.home" );

      ProjectFile p = new ProjectFile( project, oracleHome == null ? null : new File( oracleHome ) );
      
      echo( "Details for project: " + project );
      
      setProperty( p, "default.package", p.defaultPackage() );
      setProperty( p, "output.directory", p.outputDirectory().getAbsolutePath() );
      setProperty( p, "ojc.options", p.ojcOptions() );
      setProperty( p, "javac.options", p.javacOptions() );
      setProperty( p, "compiler.name", p.compilerName() );
      setProperty( p, "copy.includes", p.copyIncludes() );
      
      findContentSets( p );
      findDependencies( p );
      findLibraries( p );
    }
    catch ( IOException e )
    {
      throw new BuildException( "Failed to read project " + project + ": " + e.getMessage(), e );
    }
  }

  private void findLibraries( ProjectFile p )
  {
    echo( "Project libraries:");
    List<Library> libs = p.libraries();
    for ( Library lib : libs )
    {
      echo( "  " + lib.name() + (lib.exported() ? " (exported)" : "" ) );
      echo( "    Classpath:" );
      for ( File f : lib.classpath() )
      {
        echo( "    " + f );
      }
    }
  }

  private void findDependencies(ProjectFile p)
  {
    echo( "Project depends on:" );
    List<File> deps = p.dependencies();
    for ( File f : deps )
    {
      echo( "  " + f );
    }
  }

  private void findContentSets( ProjectFile p )
  {
    ContentSet javaContentSet = ContentSet.findJavaContentSet( p );
    setProperty( p, "java.srcpath", toPathString( javaContentSet.paths() ) );
  }

  private String toPathString( List<URL> path )
  {
    return Strings.collectionToString( urlsToStrings( path ), ':' );
  }

  private void setProperty( ProjectFile file, String propertyName, String value )
  {
    String key = file.name() + "." + propertyName;
    getProject().setProperty( key, value );
    echo( key + "=" + value );
  }

  
  private static List<String> urlsToStrings( List<URL> urls )
  {
    List<String> strings = new ArrayList<String>( urls.size() );
    for ( URL url : urls )
    {
      strings.add( url.getPath() );
    }
    return Collections.unmodifiableList( strings );
  }  

  private void echo( String message )
  {
    if ( !_echo ) return;
    log( message );
  }

}
